/**
 * @author
 * Júlio Zynger
 * DRE: 110092466
 */
package model;

import java.util.ArrayList;


public class Linguagem {
	
	private String linguagem;
	private String estado;
	private boolean naoContemSi;
	
	public Linguagem(String linguagem, String estado) {
		this.linguagem = linguagem;
		this.estado = estado;
		this.naoContemSi = isSimples();
	}

	/**
	 * Se a linguagem relativa ao estado q contiver a si mesmo, isto é, tiver uma transição para si mesmo,
	 * ela não é considerada simples. Para torná-la simples, precisaremos aplicar métodos de simplificação.
	 * @return true se a linguagem tratada é simples
	 */
	public boolean isSimples() {
		if (linguagem.contains("L(" + estado + ")")) return false;//isSimplificado = false;
		else return true; //isSimplificado = true; //se L(q) nao contiver q, esta simplificado
		//TODO
		//return isSimplificado;
	}
	
	public String simplifica(String l) {
		String[] transicoes = l.split("U");
		int cont = 0;
		
		for (String s: transicoes) {
			if (s.contains("L(" + this.estado + ")")) cont++; //conta quantas vezes L(q) aparece na linguagem do estado q
		}
		
		if (cont <= 1) this.naoContemSi = true;
		else{
			String A = "";
			
			for (String s: transicoes) {
				if (s.contains("L(" + this.estado + ")")) {
					if (A == "") A = s.replace("L(" + this.estado + ")", ""); //só entra na primeira iteração
					else A += "U" + s.replace("L(" + this.estado + ")", "");
				} 
			}
			A = corrigeParentese(A); //botei em evidencia
			A += "L(" + this.estado + ")"; //agora devolvo o termo comum
			
			String simbs = "";
			for (int i = 0; i < transicoes.length; i++) {
				if (!transicoes[i].contains("L(" + this.estado + ")")) {
					/*if (temp == "") temp = temp.concat(splitU[i]);
					else temp = temp.concat("U" + splitU[i]);*///TODO colocar o if em uma linha só
					simbs += ("U" + transicoes[i]);
				}
			}
			if(simbs.length()>1) simbs = simbs.substring(1);
			
			if (simbs.contains("U") || (simbs.length()>1) /*!= 1 && !temp.equals(""))*/) simbs = "(" + simbs + ")"; //TODO			
			
			if (simbs.equals("")) l = A; 
			else l = A + "U" + simbs;
			
			this.naoContemSi = true;
		}
		return l;
	}
	
	private String corrigeParentese(String s) {
		boolean jaTem = false;
		if (!s.equals("")){
			if(s.charAt(0) == '(' && s.charAt(s.length()-1) == ')') jaTem = true;
			else jaTem = false;
			//temParentesis = s.charAt(0) == '(' && s.charAt(s.length()-1) == ')'; //TODO
		}
		if (!jaTem) {
			if (s.length() > 1) s = "(" + s + ")";
		}
		if(jaTem && (s.length() == 3 || (s.length() == 4 && s.contains("*")))) s.replaceAll("\\(|\\)", ""); //retira os parentesis de (a) ou (ab)*
		
		/*else{ //TODO
			if (s.length() == 3 || (s.length() == 4 && s.contains("*"))) { //retira os parentesis de (a) ou (ab)*
				s.replaceAll("\\(|\\)", "");
			}
		}*/
		
		return s;
	}
	
	public /*void*/String arden() { //TODO
		String A = "", B = "";
		
		
		String[] semParent = linguagem.split("\\(|\\)"); //separar o que esta dentro dos parenteses
		for (int i = 0; i < semParent.length; i++) {
			if (semParent[i].contains("L")) {
				//if (split[i].compareTo("L") == 0 && split[i+1].compareTo(this.estado) == 0) { //TODO
				if (semParent[i].equals("L") && semParent[i+1].equals(this.estado)) { //o termo 'L(q)' foi dividido em 'L' e 'q', portanto, preciso testar i e i+1
					A = semParent[i-1];
					break;
				}
				//if (semParent[i+1].compareTo(this.estado) == 0) { //TODO
				if (semParent[i+1].equals(this.estado)){
					String[] temp = semParent[i].split("U");
					A = temp[temp.length-1].replace("L", "");
					break;
				}
			}
		}
		
		String bkpA = A;
		if (A.contains("*")) bkpA = bkpA.replace("*", "\\*");
		String regex = "U" + bkpA + "L\\("+ this.estado + "\\)|U\\(" + bkpA + "\\)L\\("+ this.estado + "\\)|" + bkpA + "L\\("+ estado + "\\)U|\\(" + bkpA + "\\)L\\("+ this.estado + "\\)U";
		
		String[] subdivLing = linguagem.split(regex); //subdividir a string em blocos de termos do tipo 'L(q)'
		for (String s: subdivLing) {
			if (!B.equals("")) B += s;
		}
		
		A = corrigeParentese(A);
		A += "*"; //estrela de kleene
		
		B = corrigeParentese(B);
		
		//this.linguagem = A + B; //TODO
		return A+B;
	}
	
	public /*void*/String substitui(String nomeEstado, String ling) { //nomeEstado é o nome do estado L(n-j) que vou procurar em L(n) TODO
		if (this.linguagem.contains("L(" + nomeEstado + ")")){
			System.out.println("entrei1");
			System.out.println("ling: " + ling);
			if(!ling.contains("L(")) {
				System.out.println("entrei2");
			}//TODO
		}
		String novaString = "";
		if (this.linguagem.contains("L(" + nomeEstado + ")") && !ling.contains("L(")) {
			if (ling.contains("U")) {
				String[] split = ling.split("U");
				String tempA = "";
				int i;
				for (i = 0; i < split.length; i++) {
					if (split[i].contains("L(" + nomeEstado + ")")) {
						if (tempA.equals("")) tempA = split[i];
						else tempA += "U" + split[i];
						ling = ling.replace(split[i], "");
						ling = ling.replace("UU", "U");
					}
				}
				tempA = corrigeParentese(simplifica(tempA));
				split = this.linguagem.split("U");
				for (i = 0; i < split.length; i++) {
					if (split[i].contains("L(" + nomeEstado + ")")) {
						split[i] = split[i].replace("L(" + nomeEstado + ")", "");
						split[i] = corrigeParentese(split[i]);
						split[i] = split[i] + ling + "U" + split[i] + tempA;
						split[i] = corrigeParentese(split[i]);
					}
				}
				String tmp = "";
				for (i = 0; i < split.length; i++) {
					/*if (tmp.equals("")) tmp = split[i];
					else tmp += "U" + split[i];*///TODO
					tmp += "U" + split[i];
				}
				if (tmp.length()>1) tmp = tmp.substring(1);
				//this.linguagem = tmp;
				novaString = tmp;
			}//else this.linguagem = this.linguagem.replace("L(" + nomeEstado + ")", ling);
			else{
				novaString = this.linguagem.replace("L(" + nomeEstado + ")", ling);
			}
			return novaString;
		}else{
			return this.linguagem;
		}
	}
	
	public String troca(String nomeEstado, String ling) {
		System.out.println("---------------\nSubstituição:");
		System.out.println("Era "+ling);
		if (this.linguagem.contains("L(" + nomeEstado + ")")){
			return corrigeParentese(this.getLinguagem().replace("L("+nomeEstado+")", ling));
		}else return this.getLinguagem();
	}
	
	/*public String distribute(String exp) {
		ArrayList<String> list = new ArrayList<String>();
		int cont = -1;
		String regex1 = ".*\\([^\\(]*\\)\\*.*";
		String regex2 = ".*\\([^\\(]*\\).*";
		while (exp.matches(regex1)) {
			int j, k;
			for (j = 0, k = exp.length(); j < k && exp.substring(j, k).matches(regex1); j++);
			j--;
			for (; j < k && exp.substring(j, k).matches(regex1); k--);
			if(k<exp.length())k++;
			String subs = exp.substring(j, k);
			list.add(subs);
			exp = exp.replace(subs, "[S"+(++cont)+"]");
		}
		while(exp.matches(regex2)){
			int j, k;
			for (j = 0, k = exp.length(); j < k && exp.substring(j, k).matches(regex2); j++);
			if(j<k)j--;
			for (; j < k && exp.substring(j, k).matches(regex2); k--);
			int l = 0;
			if(j>0){
				if(exp.charAt(j-1)==')'){
					while(exp.charAt(j-1-l)!='(')l++;
				}
				else if(exp.charAt(j-1)==']'){
					while(exp.charAt(j-1-l)!='[')l++;
				}
			}
			if(j==0) break;
			String symbol = exp.substring(j-1-l,j);
			String tmp = exp.substring(j+1, k);
			String vet[] = tmp.split("U");
			tmp = "("+tmp+")";
			String tmp1 = "";
			for (String str : vet) {
				str = symbol + str;
				tmp1 += "U" + str;
			}
			tmp1 = tmp1.substring(1);
			System.out.println("tmp="+tmp+",symbol+tmp="+symbol+tmp+",tmp1="+tmp1);
			if(symbol.equals("L")){
				String[] splitL = tmp1.split("L");
				splitL[splitL.length-1] = "("+splitL[splitL.length-1]+")";
				tmp1 = "L"+splitL[splitL.length-1];
				System.out.println("TMP1:"+tmp1);
				exp = exp.replace(symbol+tmp, tmp1);
				break;
			}
			else exp = exp.replace(symbol+tmp, tmp1);
		}
		for (int i = 0; i < list.size(); i++) {
			exp = exp.replace("[S"+i+"]", list.get(i));
		}
		return exp;
	}*/
	
	public String distribute(String exp) {
		ArrayList<String> list = new ArrayList<String>();
		int cont = -1;
		String regex1 = ".*\\([^\\(]*\\)\\*.*";
		String regex2 = ".*\\([^\\(]*\\).*";
		while (exp.matches(regex1)) {
			int j, k;
			for (j = 0, k = exp.length(); j < k && exp.substring(j, k).matches(regex1); j++);
			j--;
			for (; j < k && exp.substring(j, k).matches(regex1); k--);
			if(k<exp.length())k++;
			String subs = exp.substring(j, k);
			list.add(subs);
			exp = exp.replace(subs, "[S"+(++cont)+"]");
		}
		while(exp.matches(regex2)){
			int j, k;
			for (j = 0, k = exp.length(); j < k && exp.substring(j, k).matches(regex2); j++);
			if(j<k)j--;
			for (; j < k && exp.substring(j, k).matches(regex2); k--);
			int l = 0;
			if(j>0){
				if(exp.charAt(j-1)==')'){
					while(exp.charAt(j-1-l)!='(')l++;
				}
				else if(exp.charAt(j-1)==']'){
					while(exp.charAt(j-1-l)!='[')l++;
				}
			}
			String symbol = exp.substring(j-1-l,j);
			String tmp = exp.substring(j+1, k);
			String vet[] = tmp.split("U");
			tmp = "("+tmp+")";
			String tmp1 = "";
			for (String str : vet) {
				str = symbol + str;
				tmp1 += "U" + str;
			}
			tmp1 = tmp1.substring(1);
			exp = exp.replace(symbol+tmp, tmp1);				
		}
		for (int i = 0; i < list.size(); i++) {
			exp = exp.replace("[S"+i+"]", list.get(i));
		}
		return exp;
	}
	
	public String getLinguagem() {
		return linguagem;
	}
	
	public void setLinguagem(String l) {
		linguagem = l;
	}

	public boolean isSimplificado() {
		return naoContemSi;
	}
	
	public String getEstado() {
		return estado;
	}

	@Override
	public String toString() {
		return linguagem;
	}
}